/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
import {
  AbstractControl,
  FormBuilder,
  FormControl,
  FormGroup,
  ValidatorFn
} from '@angular/forms';
import {
  AgentsSubType,
  BaseUtilService,
  ClientManagerApiService,
  CommonConsts,
  DataMap,
  DataMapService,
  I18NService,
  KerberosAPIService
} from 'app/shared';
import {
  assign,
  each,
  filter,
  includes,
  isArray,
  isEmpty,
  isFunction,
  map,
  size,
  trim
} from 'lodash';
import { Subject } from 'rxjs';
import { AdvancedParameterComponent } from '../../nas-shared/advanced-parameter/advanced-parameter.component';
import { KerberosComponent } from 'app/business/system/security/kerberos/kerberos.component';
import { DrawModalService } from 'app/shared/services/draw-modal.service';

@Component({
  selector: 'aui-storage-advanced',
  templateUrl: './storage-advanced.component.html',
  styleUrls: ['./storage-advanced.component.less']
})
export class StorageAdvancedComponent implements OnInit {
  formGroup: FormGroup;

  resourceData;
  subResourceType;

  dataMap = DataMap;
  _includes = includes;
  sharedModeOptions = this.dataMapService
    .toArray('Shared_Mode')
    .filter(v => (v.isLeaf = true));
  authOptions = this.dataMapService
    .toArray('Nas_Share_Auth_Mode')
    .filter(item => {
      item.isLeaf = true;
      return [
        DataMap.Nas_Share_Auth_Mode.password.value,
        DataMap.Nas_Share_Auth_Mode.kerberos.value
      ].includes(item.value);
    });
  kerberosOptions = [];
  nfsAgentOptions = [];
  cifsAgentOptions = [];

  valid$ = new Subject<boolean>();
  advancedValid = false;

  ipNameErrorTip = {
    ...this.baseUtilService.requiredErrorTip,
    ...this.baseUtilService.lengthErrorTip,
    invalidMaxLength: this.i18n.get('common_valid_maxlength_label', [253]),
    invalidName: this.i18n.get('protection_no_slash_error_label'),
    invalidIp: this.i18n.get('protection_fqdn_valid_tip_label')
  };
  domainNameErrorTip = {
    invalidName: this.i18n.get('common_invalid_input_label')
  };
  usernameErrorTip = {
    ...this.baseUtilService.requiredErrorTip,
    ...this.baseUtilService.lengthErrorTip,
    invalidMaxLength: this.i18n.get('common_valid_maxlength_label', [32])
  };
  passwordErrorTip = {
    ...this.baseUtilService.requiredErrorTip,
    ...this.baseUtilService.lengthErrorTip,
    invalidMaxLength: this.i18n.get('common_valid_maxlength_label', [64])
  };

  @ViewChild(AdvancedParameterComponent, { static: false })
  advancedParameterComponent: AdvancedParameterComponent;

  constructor(
    private fb: FormBuilder,
    private i18n: I18NService,
    public dataMapService: DataMapService,
    public baseUtilService: BaseUtilService,
    private kerberosApi: KerberosAPIService,
    private drawModalService: DrawModalService,
    private clientManagerApiService: ClientManagerApiService
  ) {}

  ngOnInit(): void {
    this.initForm();
    this.getProxyOptions();
    this.updateForm();
  }

  initData(data: any) {
    this.resourceData = isArray(data) ? data[0] : data;
  }

  updateForm() {
    const advancedParams = this.resourceData.protectedObject?.extParameters;
    if (isEmpty(advancedParams)) {
      return;
    }
    const updateValue = {};
    const shareMode = [];
    const nfs = advancedParams.ip_config?.nfs;
    const cifs = advancedParams.ip_config?.cifs;
    if (!isEmpty(nfs)) {
      shareMode.push(DataMap.Shared_Mode.nfs.value);
      assign(updateValue, {
        nfs_ip: nfs.ip,
        nfs_agents: nfs.agents?.split(';')
      });
    }
    if (!isEmpty(cifs)) {
      shareMode.push(DataMap.Shared_Mode.cifs.value);
      assign(updateValue, {
        cifs_ip: cifs.ip,
        encryption: cifs.encryption === '1',
        auth_mode:
          cifs.authMode === '1'
            ? DataMap.Nas_Share_Auth_Mode.kerberos.value
            : DataMap.Nas_Share_Auth_Mode.password.value,
        kerberos: cifs.kerberosId,
        domain_name: cifs.domainName,
        username: cifs.auth?.authKey,
        password: '',
        cifs_agents: cifs.agents?.split(';')
      });
    }
    this.formGroup.patchValue({ ...updateValue, share_mode: shareMode });
  }

  validIp(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } | null => {
      if (!trim(control.value)) {
        return null;
      }
      const arr = trim(control.value).split('.');
      const reg = /^([a-zA-Z0-9]{1}|[a-zA-Z0-9][-_a-zA-Z0-9]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]{1}|[a-zA-Z0-9][-_a-zA-Z0-9]{0,61}[a-zA-Z0-9])){0,126}$/;
      for (let i = 0; i < size(arr); i++) {
        const item = arr[i];
        if (!reg.test(item)) {
          return { invalidIp: { value: control.value } };
        }
      }
      return null;
    };
  }

  enableItem(keys: Array<string>) {
    each(keys, k => this.formGroup.get(k)?.enable());
  }

  disableItem(keys: Array<string>) {
    each(keys, k => this.formGroup.get(k)?.disable());
  }

  listernForm() {
    this.formGroup.get('share_mode').valueChanges.subscribe(res => {
      if (includes(res, DataMap.Shared_Mode.nfs.value)) {
        this.enableItem(['nfs_ip', 'nfs_agents']);
      } else {
        this.disableItem(['nfs_ip', 'nfs_agents']);
      }
      if (includes(res, DataMap.Shared_Mode.cifs.value)) {
        this.enableItem(['cifs_ip', 'cifs_agents', 'auth_mode']);
        if (
          this.formGroup.get('auth_mode')?.value ===
          DataMap.Nas_Share_Auth_Mode.password.value
        ) {
          this.enableItem(['domain_name', 'username', 'password']);
        }
        if (
          this.formGroup.get('auth_mode')?.value ===
          DataMap.Nas_Share_Auth_Mode.kerberos.value
        ) {
          this.enableItem(['kerberos']);
        }
      } else {
        this.disableItem([
          'cifs_ip',
          'cifs_agents',
          'auth_mode',
          'domain_name',
          'username',
          'password',
          'kerberos'
        ]);
      }
    });
    this.formGroup.get('auth_mode').valueChanges.subscribe(res => {
      if (res === DataMap.Nas_Share_Auth_Mode.kerberos.value) {
        this.getKerberos();
        this.formGroup.get('kerberos').enable();
        this.formGroup.get('domain_name').disable();
        this.formGroup.get('username').disable();
        this.formGroup.get('password').disable();
      } else {
        this.formGroup.get('domain_name').enable();
        this.formGroup.get('username').enable();
        this.formGroup.get('password').enable();
        this.formGroup.get('kerberos').disable();
      }
    });
    this.formGroup.statusChanges.subscribe(() => {
      this.valid$.next(this.formGroup.valid && this.advancedValid);
    });
  }

  advancedStatusChange(valid) {
    this.advancedValid = valid;
    this.valid$.next(this.formGroup.valid && this.advancedValid);
  }

  initForm() {
    const ipValid = [
      this.baseUtilService.VALID.required(),
      this.validIp(),
      this.baseUtilService.VALID.maxLength(253)
    ];
    this.formGroup = this.fb.group({
      share_mode: new FormControl([], {
        validators: [this.baseUtilService.VALID.required()]
      }),
      nfs_ip: new FormControl(
        { value: '', disabled: true },
        {
          validators: ipValid
        }
      ),
      nfs_agents: new FormControl(
        { value: [], disabled: true },
        {
          validators: [this.baseUtilService.VALID.required()]
        }
      ),
      cifs_ip: new FormControl(
        { value: '', disabled: true },
        {
          validators: ipValid
        }
      ),
      cifs_agents: new FormControl(
        { value: [], disabled: true },
        {
          validators: [this.baseUtilService.VALID.required()]
        }
      ),
      auth_mode: new FormControl(
        { value: '', disabled: true },
        {
          validators: [this.baseUtilService.VALID.required()]
        }
      ),
      kerberos: new FormControl(
        { value: '', disabled: true },
        {
          validators: [this.baseUtilService.VALID.required()]
        }
      ),
      domain_name: new FormControl(
        { value: '', disabled: true },
        {
          validators: [
            this.baseUtilService.VALID.name(
              CommonConsts.REGEX.nasshareDomain,
              false
            )
          ]
        }
      ),
      username: new FormControl(
        { value: '', disabled: true },
        {
          validators: [
            this.baseUtilService.VALID.required(),
            this.baseUtilService.VALID.maxLength(32)
          ]
        }
      ),
      password: new FormControl(
        { value: '', disabled: true },
        {
          validators: [
            this.baseUtilService.VALID.required(),
            this.baseUtilService.VALID.maxLength(64)
          ]
        }
      ),
      encryption: new FormControl(false)
    });

    this.listernForm();
  }

  createKerberos() {
    const kerberosComponent = new KerberosComponent(
      this.i18n,
      this.drawModalService
    );
    kerberosComponent.create(undefined, kerberos => {
      this.getKerberos(() => {
        this.formGroup.get('kerberos').setValue(kerberos);
      });
    });
  }

  setKerberosOptions(recordsTemp, callback) {
    this.kerberosOptions = map(recordsTemp, item => {
      return {
        ...item,
        label: item.name,
        isLeaf: true
      };
    });
    if (isFunction(callback)) {
      callback();
    }
  }

  getKerberos(
    callback = () => {},
    recordsTemp = [],
    startPage = CommonConsts.PAGE_START
  ) {
    this.kerberosApi
      .queryAllKerberosUsingGET({
        pageSize: CommonConsts.PAGE_SIZE_MAX,
        startPage: startPage
      })
      .subscribe(res => {
        if (isArray(res.items)) {
          recordsTemp = [...recordsTemp, ...res.items];
        }
        if (
          res.total === 0 ||
          startPage === Math.floor(res.total / CommonConsts.PAGE_SIZE_MAX)
        ) {
          this.setKerberosOptions(recordsTemp, callback);
          return;
        }
        startPage++;
        this.getKerberos(callback, recordsTemp, startPage);
      });
  }

  getProxyOptions(recordsTemp = [], startPage = CommonConsts.PAGE_START) {
    const params = {
      pageNo: startPage,
      pageSize: CommonConsts.PAGE_SIZE_MAX,
      conditions: JSON.stringify({
        pluginType: AgentsSubType.NasShare
      })
    };
    this.clientManagerApiService
      .queryAgentListInfoUsingGET(params)
      .subscribe(res => {
        if (isArray(res.records)) {
          recordsTemp = [...recordsTemp, ...res.records];
        }
        if (
          startPage ===
            Math.floor(res.totalCount / CommonConsts.PAGE_SIZE_MAX) ||
          res.totalCount === 0
        ) {
          const hostArray = [];
          each(recordsTemp, item => {
            hostArray.push({
              ...item,
              key: item.uuid,
              value: item.rootUuid || item.parentUuid,
              label: `${item.name}(${item.endpoint})`,
              isLeaf: true
            });
          });
          this.nfsAgentOptions = filter(
            hostArray,
            host =>
              host.linkStatus ===
              DataMap.resource_LinkStatus_Special.normal.value
          );
          this.cifsAgentOptions = filter(
            hostArray,
            host =>
              host.linkStatus ===
              DataMap.resource_LinkStatus_Special.normal.value
          );
          return;
        }
        this.getProxyOptions(recordsTemp, startPage);
      });
  }

  onOK() {
    const ip_config = {};
    const mode = this.formGroup.get('share_mode')?.value;
    const authMode = this.formGroup.get('auth_mode')?.value;
    if (includes(mode, DataMap.Shared_Mode.cifs.value)) {
      assign(ip_config, {
        cifs: {
          ip: this.formGroup.get('cifs_ip')?.value,
          agents: this.formGroup.get('cifs_agents')?.value.join(';'),
          shareMode: DataMap.Shared_Mode.cifs.value,
          authMode:
            authMode === DataMap.Nas_Share_Auth_Mode.kerberos.value ? '1' : '0',
          kerberosId: this.formGroup.get('kerberos')?.value,
          encryption: this.formGroup.get('encryption')?.value ? '1' : '0',
          domainName: this.formGroup.get('domain_name')?.value,
          auth: {
            authType: authMode,
            authKey: this.formGroup.get('username')?.value,
            authPwd: this.formGroup.get('password')?.value
          }
        }
      });
    }
    if (includes(mode, DataMap.Shared_Mode.nfs.value)) {
      assign(ip_config, {
        nfs: {
          ip: this.formGroup.get('nfs_ip')?.value,
          agents: this.formGroup.get('nfs_agents')?.value.join(';')
        }
      });
    }

    return {
      ext_parameters: {
        ip_config,
        ...this.advancedParameterComponent.onOK().ext_parameters
      }
    };
  }
}
